﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using System.Windows.Forms;

namespace TotalCrytography.Zip
{
    public class Zip
    {


        #region code nguồn mở đã được sửa chữa, http://www.eggheadcafe.com/tutorials/aspnet/9ce6c242-c14c-4969-9251-af95e4cf320f/zip--unzip-folders-and-f.aspx
        public class Item
        {
            public string FilePath;
            public string ParentFolder;
            public Item(string filepath, string parentfolder)
            {
                FilePath = filepath;
                ParentFolder = parentfolder;
            }
        }


        // inputFoldersAndFiles: tập hợp các thư mục, tập tin cần nén
        public static void ZipFiles(List<string> inputFoldersAnhFiles, string outputPathAndFile, string password, int level)
        {
            List<Item> ar = GenerateFileList(inputFoldersAnhFiles); // generate file list

            for (int i = 0; i < inputFoldersAnhFiles.Count; i++)
                inputFoldersAnhFiles[i].Replace("\\\\", "\\");

            FileStream ostream = null;
            byte[] obuffer;
            
            //FileStream fs = new FileStream(outputPathAndFile, FileMode.Create, FileAccess.Read, FileShare.ReadWrite);
            ZipOutputStream oZipStream = new ZipOutputStream(File.Create(outputPathAndFile)); // create zip stream
            //ZipOutputStream oZipStream = new ZipOutputStream(fs);
            if (password != null && password != String.Empty)
                oZipStream.Password = password;
            oZipStream.SetLevel(level); // maximum compression
            ZipEntry oZipEntry;
            foreach (Item Fil in ar) // for each file, generate a zipentry
            {
                oZipEntry = new ZipEntry(Fil.FilePath.Replace(Fil.ParentFolder, ""));
                oZipStream.PutNextEntry(oZipEntry);
                int count;
                if (!Fil.FilePath.EndsWith(@"/")) // if a file ends with '/' its a directory
                {
                    //ostream = File.OpenRead(Fil.FilePath);
                    ostream = new FileStream(Fil.FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    obuffer = new byte[1024 * 4];
                    while ((count = ostream.Read(obuffer, 0, obuffer.Length)) != 0)
                    {
                        oZipStream.Write(obuffer, 0, count);
                    }
                }
            }
            oZipStream.Finish();
            oZipStream.Close();
            //fs.Close();
            if (ostream != null)
                ostream.Close();
        }
        // Giải nén
        public static void UnZipFiles(string zipPathAndFile, string outputFolder, string password, bool deleteZipFile)
        {
            ZipInputStream s = new ZipInputStream(File.OpenRead(zipPathAndFile));

            if (password != null && password != String.Empty)
                s.Password = password;
            ZipEntry theEntry;
            string tmpEntry = String.Empty;
            string directoryName = outputFolder;

            DirectoryInfo di = new DirectoryInfo(directoryName);
            if (di.Root.ToString() == di.ToString()) // ổ đĩa
                directoryName = directoryName.Remove(2);
            else
            {
                // create directory 
                if (directoryName != "" && !Directory.Exists(directoryName))
                {
                    Directory.CreateDirectory(directoryName);
                }
            }

            while ((theEntry = s.GetNextEntry()) != null)
            {

                string fileName = Path.GetFileName(theEntry.Name);

                if (fileName != String.Empty)
                {
                    if (theEntry.Name.IndexOf(".ini") < 0)
                    {
                        string fullPath = directoryName + "\\" + theEntry.Name;
                        fullPath = fullPath.Replace("\\ ", "\\");
                        string fullDirPath = Path.GetDirectoryName(fullPath);
                        if (!Directory.Exists(fullDirPath)) Directory.CreateDirectory(fullDirPath);
                        FileStream streamWriter = File.Create(fullPath);
                        int size = 1024 * 4;
                        byte[] data = new byte[size];
                        while (true)
                        {
                            try
                            {
                                size = s.Read(data, 0, data.Length);
                            }
                            catch (System.Exception ex)
                            {
                                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                                return;
                            }
                            
                            if (size > 0)
                            {
                                streamWriter.Write(data, 0, size);
                            }
                            else
                            {
                                break;
                            }
                        }
                        streamWriter.Close();
                    }
                }
                else // Folder
                {
                    Directory.CreateDirectory(directoryName + "\\" + theEntry.Name.Remove(theEntry.Name.Length - 1));
                }
            }
            s.Close();
            if (deleteZipFile)
                File.Delete(zipPathAndFile);
        }
        // Lấy danh sách tập tin, thư mục các cấp
        private static List<Item> GenerateFileList(string Dir, string parent)
        {
            List<Item> fils = new List<Item>();
            bool Empty = true;
            foreach (string file in Directory.GetFiles(Dir)) // add each file in directory
            {
                fils.Add(new Item(file, parent));
                Empty = false;
            }

            if (Empty)
            {
                if (Directory.GetDirectories(Dir).Length == 0)
                // if directory is completely empty, add it
                {
                    fils.Add(new Item(Dir + @"/", parent));
                }
            }

            foreach (string dirs in Directory.GetDirectories(Dir)) // recursive
            {
                fils.AddRange(GenerateFileList(dirs, parent));
                foreach (Item obj in GenerateFileList(dirs, parent))
                {
                    fils.Add(obj);
                }
            }
            return fils; // return file list
        }
        private static List<Item> GenerateFileList(List<string> FoldersAndFiles)
        {
            List<Item> result = new List<Item>();

            foreach (string item in FoldersAndFiles)
            {
                DirectoryInfo di = Directory.GetParent(item);
                string parent = di.ToString();
                if (di.ToString() != di.Root.ToString()) // kô phải ổ đĩa
                    parent += @"\";

                DirectoryInfo file = new DirectoryInfo(item);// Path.GetFileName(item);
                if (file.Attributes == FileAttributes.Directory) // Thư mục
                {

                    List<Item> temp = GenerateFileList(item, parent);
                    result.AddRange(temp);
                }
                else // Tập tin
                    result.Add(new Item(item, parent));
            }
            return result;
        }
        #endregion
    }
}
